'''
Created on Dec 2, 2012
CuPy security module.
@see: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html for more information
about the security parameters and their functionalities.
@author: quirino
'''

from imports import pycurl

SSL_VERION_MAP = {
            "DEFAULT" : pycurl.SSLVERSION_DEFAULT,
            "TLSv1" : pycurl.SSLVERSION_TLSv1,
            "SSLv2" : pycurl.SSLVERSION_SSLv2,
            "SSLv3" : pycurl.SSLVERSION_SSLv3
    }

class SecurityHandler(object):
    '''
    Defines the archetype of a security handler implementation
    '''

    def __init__(self, ssl_version, cert_info=1):
        '''
        Initializes the common structures for SecurityHandler implementations
        @param ssl_version: version of SSL/TSL version to use. Default attempt 
        to automatically figure out the remote SSL verification protocol.
        @param cert_info: enable certificate chain info gatherer. Default to 1
        '''
        if ssl_version in SSL_VERION_MAP :
            self.ssl_version = SSL_VERION_MAP[ssl_version]
        else :
            self.ssl_version = SSL_VERION_MAP["DEFAULT"]
        self.cert_info = cert_info
    
    def configure(self, conn): 
        """
        Configure the connection wrapper.
        """
        raise NotImplementedError()
#        conn.setoption(pycurl.SSLVERSION, self.ssl_version)
#        conn.setoption(pycurl.CERTINFO, self.cert_info)

class PrivateKeySecurityHandler(SecurityHandler):
    
    def __init__(self, pkey, ssl_version="DEFAULT", cert_info=1):
        """
        Initializes the private key based security handler
        @param pkey: the PrivateKey information wrapper
        @param ssl_version: the SSL version to use.
        @param cert_info: flag enable or disable the certificate information 
        gatherer
        """
        super(PrivateKeySecurityHandler, self).__init__(ssl_version, cert_info)
        self.pkey = pkey
        
        def configure(self, conn):
            """
            Configure the connection wrapper.
            """
            conn.option(pycurl.SSLKEY, self.pkey.pkey)
            conn.option(pycurl.SSLKEYPASSWD, self.pkey.pkey_pwd)
            conn.option(pycurl.SSLKEYTYPE, self.pkey.pkey_type)
            conn.option(pycurl.SSLVERSION, self.ssl_version)
            
        
class SSLSecurityHandler(SecurityHandler):
    
    def __init__(self, cert, ssl_version="DEFAULT", cert_info=1):
        """
        Initializes the SSL security key based security handler
        @param cert: the Certificate information wrapper
        @param ssl_version: the SSL version to use.
        @param cert_info: flag enable or disable the certificate information 
        gatherer
        """
        super(SSLSecurityHandler, self).__init__(ssl_version, cert_info)
        self.cert = cert
        
    def configure(self, conn):
        """
        Configure the connection wrapper.
        """
        if self.cert.cert is not None:
            conn.option(pycurl.SSLCERT, self.cert.cert)
        conn.option(pycurl.SSLCERTTYPE, self.cert.cert_type)
        conn.option(pycurl.SSL_VERIFYPEER, self.cert.vpeer)
        if self.cert.cainfo is not None:
            conn.option(pycurl.CAINFO, self.cert.cainfo)
        if self.cert.issuecert is not None:
            conn.option(pycurl.ISSUERCERT, self.cert.issuecert)
        if self.cert.capath is not None:
            conn.option(pycurl.CAPATH, self.cert.capath)
        conn.option(pycurl.SSL_VERIFYHOST, self.cert.vhost)
        conn.option(pycurl.SSLVERSION, self.ssl_version)

class Certificate(object):
    """
    Certificate information wrapper
    """
    def __init__(self, cert=None, cert_type="PEM", verify_peer=1, cainfo=None, 
                 issuecert=None, capath=None, verify_host=2):
        """
        Initializes the certificate wrapper
        @param cert: the client certificate file name. default format is PEM; 
        it can be changed using the cert_type option. Make sense to use this 
        option even if peer verification is disabled.
        @param cert_type: the client certificate type default to PEM. Valid 
        options are: PEM, DER. Make sense to use this option even if peer 
        verification is disabled.
        @param verify_peer: determines if the authenticity of the peer 
        certificate should be verified, default value is is 1 means verify the 
        authenticity. Valid options are 0,1
        @param cainfo: a path to a file naming one or more certificate to 
        verify with the peer. This make sense only if the peer verification is 
        enabled. If not set cURL defaults this parameter to the path where 
        libcurl CA certificate bundle is supposed to be stored.
        @param issuecert: a string naming a file holding a CA certificate in 
        PEM format. Set this option causes a second check to be performed to 
        verify the host identity. This make sense only if the peer verification 
        is enabled.
        @param capath: a string naming a directory containing multiple CA 
        certificates to have to verify with the peer. This make sense only if 
        the peer verification is enabled. If libcurl is built against OpenSSL, 
        the certificate directory must be prepared using the openssl c_rehash 
        utility.
        @param verify_host: determines whether the server certificate authenticity 
        is verified for the server it is known as. Valid options are o,1,2. The 
        default value is set to 2. In this case during the SSL verification 
        the server certificate authenticity is verified checking that the server 
        certificate indicate that the server is the one the connection is performed 
        to. If set to 1 cURL will return an error. When set to 0 the host 
        verification is disabled 
        """
        self.cert = cert
        self.cert_type = cert_type if cert_type in ("PEM", "DER") else "PEM"
        
        self.vpeer = verify_peer if verify_peer in (0,1) else 1
        self.cainfo = cainfo
        self.issuecert=issuecert
        self.capath = capath
        
        self.vhost = verify_host if verify_host in (0,2) else 2
        

class PrivateKey(object):
    """
    Private key information wrapper class
    """
    def __init__(self, pkey="", pkey_type="PEM", pkey_pwd="", crypto_engine=None):
        """
        Initializes the private key wrapper
        @param pkey: the private key file name. Default format is PEM, it can 
        be changed setting the pkey_type parameter
        @param pkey_type: the private key format, default value is PEM, 
        supported format are: PEM, DER, ENG. If ENG is specified, the private 
        key can be loaded from a crypto engine. In this case the pkey parameter 
        is used as identifier for the crypto engine set on the security handler 
        via the ssl_engine parameter.
        @param pkey_pwd: the password required by the private key.
        @param crypto_engine: string parameter used as the identifier for the 
        crypto engine you want to use for your private key.
        """
        self.pkey = pkey
        self.pkey_type = pkey_type
        self.pkey_pwd = pkey_pwd